#include "RtpClient.h"
#include "RtpUnPack.h"
#include "DecodeFrame.h"
extern "C" {
#include "bmp/li_bitmap.h"
#include "util/Log.h"
}

static int tcpSock, udpSock;
RtpUnPack *unpack;
unsigned char mediaBuf[MAX_BUFFER_SIZE];
unsigned char picBuf[352 * 288 * 2];
FILE *bits = NULL;
int recvIndex = 0;
int isFindIFrame = 0;
void save2FileNew(int len);

CClientManager *gClientManager;
CRtpClient* gRtpClient;

FILE* OpenBitstreamFile(char *fn) {
    FILE *file = NULL;
    if (NULL == (file = fopen(fn, "wb+"))) {
        WriteLog(LOG_ERROR,"open file error\n");
        return NULL;
    }
    return file;
}

CRtpClient::CRtpClient(char* ip, unsigned int rtspPort, char* mode, char* url, char* rootPath, long lType) {
    mServerIP = ip;
    string sMode = mode;
    if (strcmp(sMode.c_str(), "tcp") == 0)
        mUseTcp = 1;
    else
        mUseTcp = 0;
    mUrl = url;
    mRootPath = rootPath;
    mRtspPort = rtspPort;
    mCseq = 0;
    mIsRtpRunning = 0;
    mMsgkey = (key_t)lType;
    mCamState = CAM_STATE_PENDDING;
}

CRtpClient::CRtpClient(void) {
}

CRtpClient::~CRtpClient(void) {
}

void CRtpClient::InitClient() {
    char* localIP = GetLocalIP(WLAN_NAME);

    if (localIP == NULL) {
        localIP = GetLocalIP(ETH_NAME);
    }
    if (localIP == NULL) {
        //TODO, need modify
        localIP=LOCAL_IP;
        WriteLog(LOG_INFO,"Try LocalIP = ",localIP);
    //    exit(1);
    }
    mLocalIP=localIP;
    printf("LocalIP = %s\n",mLocalIP.c_str());
    WriteLog(LOG_INFO,"LocalIP = %s\n", mLocalIP.c_str());

    InitRtspSocket();
    if (mUseTcp)
        InitTcpSocket();
    else
        InitUdpSocket();
}

void CRtpClient::InitTcpSocket() {
    struct sockaddr_in addr;
    if ((tcpSock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        exit(1);
    }
    std::cout << "TCP SOCKET=" << tcpSock << std::endl;
    //设置端口状态
    int on = 1;
    setsockopt(tcpSock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(int));
    //设置以不可阻断的方式处理套接字
    SetNonBlocking(tcpSock);
    /* 填写sockaddr_in结构*/
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(getRtpPort());
    addr.sin_addr.s_addr = INADDR_ANY;
    /* 绑定地址和端口信息 */
    if ((bind(tcpSock, (struct sockaddr *) &addr, sizeof(addr))) == -1) {
        perror("bind");
        exit(errno);
    } else{
        WriteLog(LOG_ERROR,"bind address to socket.");
    }

    listen(tcpSock, 5);
}
void CRtpClient::InitUdpSocket() {
    struct sockaddr_in s_addr;
    /* 创建 socket , 关键在于这个 SOCK_DGRAM */
    if ((udpSock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        exit(errno);
    } else
        std::cout << "UDP SOCKET=" << udpSock << std::endl;
    //设置端口状态
    int on = 1;
    setsockopt(udpSock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(int));
    //设置以不可阻断的方式处理套接字
    SetNonBlocking(udpSock);
    /* 设置地址和端口信息 */
    memset(&s_addr, 0, sizeof(struct sockaddr_in));
    s_addr.sin_family = AF_INET;
    s_addr.sin_port = htons(getRtpPort());
    s_addr.sin_addr.s_addr = INADDR_ANY;
    /* 绑定地址和端口信息 */
    if ((bind(udpSock, (struct sockaddr *) &s_addr, sizeof(s_addr))) == -1) {
        perror("bind");
        exit(errno);
    } else{
        WriteLog(LOG_ERROR,"bind address to socket.");
    }

}
void CRtpClient::InitRtspSocket() {
    char* str;
    struct sockaddr_in addr;
    if ((rtspSock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket");
        exit(1);
    }
    std::cout << "RTSP SOCKET=" << rtspSock << std::endl;
    // init sockaddr_in
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(mRtspPort);
    addr.sin_addr.s_addr = inet_addr(mServerIP.c_str());
    // Try to connect to server
    if (connect(rtspSock, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
        perror("connect");
        exit(1);
    }

    //Send Options
    cout << "================Options===============" << endl;
    Send(getOptions());

    //Send Describe
    cout << "================Describe===============" << endl;
    Send(getDescribe());

    //Send Setup
    cout << "================Setup===============" << endl;
    char* strResSetup = Send(getSetup());

    // get Session ID
    cout << "================getSessions===============" << endl;
    setSession(strResSetup);
    cout << "session = " << mSession.c_str() << endl;
}

void CRtpClient::CreateRecvThread() {
    memset(&rtspID, 0, sizeof(rtspID));
    memset(&udpID, 0, sizeof(udpID));
    memset(&tcpID, 0, sizeof(tcpID));

    mIsRtpRunning = 1;
    int err;
    err = pthread_create(&rtspID, NULL, MediaThreadRtsp, (CRtpClient*) this);
    if (mUseTcp) {
        err = pthread_create(&tcpID, NULL, MediaThreadTcp, (CRtpClient*) this);
    } else {
        err = pthread_create(&udpID, NULL, MediaThreadUdp, (CRtpClient*) this);
    }
}

void CRtpClient::CreateMsgThread() {
    memset(&msgID, 0, sizeof(msgID));

    mIsMsgQueryRunning = 1;
    int err;
    err = pthread_create(&msgID, NULL, MsgQueryThread, (CRtpClient*) this);

}

void* CRtpClient::MediaThreadTcp(void* paramPtr) {
    CRtpClient* client = (CRtpClient*) paramPtr;

    // 初始化Decoder
    InitDecoder(352, 288);

    struct sockaddr_in their_addr;
    socklen_t sin_size = sizeof(struct sockaddr_in);
    int new_fd = accept(tcpSock, (sockaddr*) &their_addr, &sin_size);
    //设置以不可阻断的方式处理套接字
    //    SetNonBlocking(new_fd);
    //    close(tcpSock);

    while (client->mIsRtpRunning) {
        //        memset(mediaBuf, 0, sizeof(mediaBuf));
        int len = recv(new_fd, mediaBuf, sizeof(mediaBuf) - 1, 0);
        if (len < 0) {
            perror("recv");
            usleep(1000000);
            continue;
        }
        std::cout << "媒体流长度：" << len << std::endl;

        save2FileNew(len);

        //TODO 查询客户端列表，向每个Playing的客户端发送数据
        gClientManager->sendToClient(mediaBuf, len);
    }
    fclose(bits);
    close(new_fd);
    // 结束Decoder
    UninitDecoder();

    return NULL;
}
void* CRtpClient::MediaThreadUdp(void* paramPtr) {
    unsigned char rtpData[MAX_BUFFER_SIZE];
    CRtpClient* client = (CRtpClient*) paramPtr;
    struct sockaddr_in c_addr;
    socklen_t addr_len;
    int len;
    /* 循环接收数据 */
    addr_len = sizeof(c_addr);
    cout << "开始接收文件" << endl;
    // 初始化Decoder
    InitDecoder(352, 288);

    while (client->mIsRtpRunning) {
        len = recvfrom(udpSock, mediaBuf, sizeof(mediaBuf) - 1, 0,
                (struct sockaddr *) &c_addr, &addr_len);
        if (len < 0) {
        //    perror("recvfrom");
            usleep(1000000);
            continue;
        }
        // std::cout << "媒体流长度：" << len << std::endl;
        //	printf("收到来自%s:%d的消息:%s\r\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port),mediaBuf);

        //TODO 查询客户端列表，向每个Playing的客户端发送数据
        memcpy(rtpData,mediaBuf,len);

        save2FileNew(len);

        gClientManager->sendToClient(rtpData, len);
    }
    cout << "文件接收结束" << endl;
    fclose(bits);
    // 结束Decoder
    UninitDecoder();

    return NULL;
}

void* CRtpClient::MediaThreadRtsp(void* paramPtr) {
    CRtpClient* client = (CRtpClient*) paramPtr;
    char c;
    while (1) {
//        client->ShowMenu();
//        cin >> c;
        if (client->mCamState == CAM_STATE_PENDDING) {
            usleep(1000000);
            client->Send(client->getPlay());
            client->mCamState = CAM_STATE_PLAYING;
            usleep(10000000);
        } else if (client->mCamState == CAM_STATE_PLAYING) {
            client->Send(client->getOptions());
            usleep(10000000);
        } else if (client->mCamState == CAM_STATE_STOP) {
            client->Send(client->getTearDown());
        } else if (client->mCamState == CAM_STATE_QUIT) {
            client->Send(client->getTearDown());
            if (client->mUseTcp) {
                client->mIsRtpRunning = 0;
                client->mIsMsgQueryRunning = 0;
                //	close(udpSock);
                pthread_exit(&(client->tcpID));
            } else {
                client->mIsMsgQueryRunning = 0;
                client->mIsRtpRunning = 0;
                //	close(udpSock);
                pthread_exit(&(client->udpID));
            }
            break;
        }
        sleep(1);
    }
    return NULL;
}

void* CRtpClient::MsgQueryThread(void* paramPtr) {
    /*用户自定义消息缓冲区*/
    QueueMsgbuf msgbuffer;

    CRtpClient* client = (CRtpClient*) paramPtr;

    int qid;/*消息队列标识符*/
    int msglen;

//    /*获取键值*/
//    if ((msgkey = ftok(PATH_NAME, PROJ_ID)) == -1) {
//        perror("ftok error!\n");
//        exit(1);
//    }

    if ((qid = msgget(client->mMsgkey, IPC_CREAT | 0660)) == -1) {
        perror("msgget error!\n");
        exit(1);
    }
    while (client->mIsMsgQueryRunning) {
//        printf("begin recv msg from msgbuffer\n");
        //TODO read msg from msg queue
        if (msgrcv(qid, &msgbuffer, QMSG_SIZE, 0, IPC_NOWAIT) == -1)
        /*if queue is empty, block here*/
        {
        //    perror("Server msgrcv error!\n");
            usleep(1000000);
            continue;
//            break;
        }
        fputs(msgbuffer.strSession, stdout);
        fputs("\n", stdout);

        /*
         * create new client.
         */
        if(msgbuffer.iCommand==CMD_SETUP){
            WriteLog(LOG_INFO,"create a new client.");
            gClientManager->createNewClient(msgbuffer.iCommand,msgbuffer.iMarkTcp,msgbuffer.iPort,
                    msgbuffer.strAddr,msgbuffer.strSession);
        }else{
            gClientManager->manageClient(msgbuffer.iCommand,msgbuffer.strSession);
            if(CMD_STOP == msgbuffer.iCommand){
                client->mCamState = CAM_STATE_STOP;
            }
        }

        usleep(1000000);
    }

    return NULL;
}

void CRtpClient::ShowMenu() {
//    printf("s-play, t-teardown, x-quit\n");
}
void CRtpClient::YourChoose() {

}

char* CRtpClient::GetLocalIP(char* name) {
    int sock;
    struct sockaddr_in sin;
    struct ifreq ifr;

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock == -1) {
        perror("socket");
        return NULL;
    }

    strncpy(ifr.ifr_name, name, IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ - 1] = 0;

    if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) {
        perror("ioctl");
        return NULL;
    }
    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    char* temp = inet_ntoa(sin.sin_addr);
    close(sock);
    return temp;
}

bool CRtpClient::SetNonBlocking(int& Sock) {
    int opts;
    opts = fcntl(Sock, F_GETFL);
    if (opts < 0) {
        perror("fcntl(sock,GETFL)");
        return false;
    }
    opts |= O_NONBLOCK;
    if (fcntl(Sock, F_SETFL, opts) < 0) {
        printf("fcntl(sock,SETFL,opts) error: %s", strerror(errno));
        return false;
    }
    return true;
}

void CRtpClient::Run() {
    bits = OpenBitstreamFile("/home/zgx/bsu.h264");
    int hr;
    unpack = new RtpUnPack(hr);

    InitClient();
    //Create Rtsp and Rtp Thread
    CreateRecvThread();
    CreateMsgThread();

    gClientManager = new CClientManager();

    //等待所有子线程结束
    if (mUseTcp) {
        pthread_join(tcpID, NULL);
    } else {
        pthread_join(udpID, NULL);
    }
    pthread_join(rtspID, NULL);
    pthread_join(msgID, NULL);

    delete gClientManager;
}



int iTemp = 0;
int nalLen;

bool bFirst = true;
bool bFindPPS = true;

int bytesRead = 0;
int NalBufUsed = 0;
int SockBufUsed = 0;

char NalBuf[40980]; // 40k
uint8_t videoVideoData[352 * 288 * 2];
/*
 * 读取到的数据
 */
char SockBuf[2048];

void save2FileNew(int len) {
    unsigned char *pRtpData = (unsigned char*) mediaBuf;
    int inSize = len;
    int outSize;
    unsigned char *pFrame = unpack->Parse_RTP_Packet(pRtpData, inSize, &outSize, gClientManager);

    //	printf("len = %d\n", outSize);
    if (pFrame != NULL) {
        // printf("%d\t len = %d\n", recvIndex++, outSize);
        //		if(isFindIFrame==0){
        //			if(outSize>1500)
        //				isFindIFrame = 1;
        //			else
        //				return;
        //		}

        /*
         char tmpname[L_tmpnam];
         char *filename;
         FILE *fp;
         strcpy(tmpname, "/home/zgx/tmp_pic/dfXXXXXX.bmp");//file name:df...
         filename = mktemp(tmpname);//generate tempfile
         printf("temporary file name:%s\n", filename);

         fp = tmpfile();
         if (fp)
         printf("temporary file oepn.\n");
         else
         perror("error");
         */

        //		memset(picBuf,0,sizeof(picBuf));
        //解析Frame
        //
//        srand(int(time(0)));
//
//        char tmpname[32];
//        sprintf(tmpname, "/home/zgx/tmp_pic/%03d.bmp", rand() % 1000);

//        int picLen = DecoderNal((uint8_t*) pFrame, 2 * 352 * 288,
//                (uint8_t*) picBuf);

        //        FILE *file = OpenBitstreamFile(tmpname);
        //        if (file != NULL) {
        //            printf("begin fwrite\n");
        //            fwrite(picBuf, 1, picLen, file);
        //            printf("end fwrite\n");
        //            fclose(file);
        //        }
//        SaveRGB565_BmpFile(picBuf, 2 * 352 * 288, 352, 288, tmpname);

            if (bits != NULL) {
            fwrite(pFrame, 1, outSize, bits);
        }
    }
}

